﻿using HslCommunication;                                               // 引入HSL通信库
using HslCommunication.Core;                                          // HSL核心功能
using HslCommunication.Profinet.Siemens;                             // HSL西门子PLC实现
using Microsoft.Win32;                                                // 注册表操作
using Newtonsoft.Json;                                                // JSON序列化
using Sunny.UI;                                                       // SunnyUI控件
using Sunny.UI.Win32;                                                 // SunnyUI的Win32扩展
using System;                                                         // 基础命名空间
using System.Collections;                                             // 集合接口
using System.Collections.Generic;                                     // 泛型集合
using System.ComponentModel;                                          // 组件模型
using System.Data;                                                    // 数据相关
using System.Diagnostics;                                             // 调试/日志
using System.Drawing;                                                 // GDI+
using System.Globalization;
using System.IO;                                                      // IO操作
using System.IO.Ports;                                                // 串口
using System.Linq;                                                    // LINQ
using System.Runtime.CompilerServices;                                // 编译器服务
using System.Text;                                                    // 文本编码
using System.Text.RegularExpressions;
using System.Threading;                                               // 线程
using System.Threading.Tasks;                                         // 任务并行库
using System.Timers;                                                  // 定时器
using System.Windows.Forms;                                           // WinForm控件
using static System.Windows.Forms.VisualStyles.VisualStyleElement;    // 样式元素
using Timer = System.Windows.Forms.Timer;                             // 显式指定Timer别名

namespace MMD_AcquisitionSystem                                       // 项目命名空间
{
    public partial class FrmMain : UIForm                             // 主窗体类，继承SunnyUI的UIForm
    {
        public FrmMain()                                              // 构造函数
        {
            InitializeComponent();                                    // 窗体设计器初始化
            InitParam();                                              // 自定义初始化
            btn_DisConnect1.Enabled = false;                          // 禁用电子秤断开按钮
            btn_DisConnect2.Enabled = false;                          // 禁用电阻仪断开按钮
            btn_DisConnectPLC.Enabled = false;                        // 禁用PLC断开按钮
            btn_DisConnect3.Enabled = false;// 禁用万用表断开按钮
            btn_DisConnect4.Enabled = false;// 禁用数字绝缘表断开按钮
            this.Load += FrmMain_Load;                                // 注册窗体加载事件
            this.FormClosed += FrmMain_FormClosed;                    // 注册窗体关闭事件

            // 授权设置
            if (!HslCommunication.Authorization.SetAuthorizationCode("fe49cdb6-b388-4c05-9b66-0e3f1ad3627f")) // 设置HSL授权码
            {
                UIMessageBox.ShowError("Authorization failed! The current program can only be used for 8 hours!"); // 授权失败提示
                return;                                               // 退出构造函数
            }
        }

        #region 窗体关闭或电脑关机,释放资源
        private const int WM_QUERYENDSESSION = 0x0011;                // 系统关机消息

        protected override void WndProc(ref Message m)                // 重写消息处理
        {
            if (m.Msg == WM_QUERYENDSESSION)                          // 如果是关机消息
            {
                CleanupResources();                                   // 清理资源
            }
            base.WndProc(ref m);                                      // 继续处理
        }

        private void CleanupResources()                               // 统一清理资源方法
        {
            // 断开PLC连接
            if (isPLCConnected)                                       // 如果PLC已连接
            {
                DisconnectPLC();                                      // 断开PLC
            }

            // 断开电子秤串口
            if (scaleSerialPort != null && scaleSerialPort.IsOpen)    // 如果电子秤串口已打开
            {
                try
                {
                    scaleSerialPort.Close();                          // 关闭串口
                    scaleSerialPort.Dispose();                        // 释放资源
                }
                catch { }                                             // 忽略异常
                scaleSerialPort = null;                               // 置空引用
            }

            // 断开电阻测试仪串口
            if (resistorTesterSerialPort != null && resistorTesterSerialPort.IsOpen) // 如果电阻仪串口已打开
            {
                try
                {
                    resistorTesterSerialPort.Close();                 // 关闭串口
                    resistorTesterSerialPort.Dispose();               // 释放资源
                }
                catch { }                                             // 忽略异常
                resistorTesterSerialPort = null;                      // 置空引用
            }
            // 断开万用表串口
            if (multimeterSerialPort != null && multimeterSerialPort.IsOpen) // 如果万用表已打开
            {
                try
                {
                    multimeterSerialPort.Close();                 // 关闭串口
                    multimeterSerialPort.Dispose();               // 释放资源
                }
                catch { }                                             // 忽略异常
                multimeterSerialPort = null;                      // 置空引用
            }
            // 断开数字绝缘表串口
            if (numberMeterSerialPort != null && numberMeterSerialPort.IsOpen) // 如果万用表已打开
            {
                try
                {
                    numberMeterSerialPort.Close();                 // 关闭串口
                    numberMeterSerialPort.Dispose();               // 释放资源
                }
                catch { }                                             // 忽略异常
                numberMeterSerialPort = null;                      // 置空引用
            }
        }
        #endregion

        #region 变量与属性
        private object serialPortLock = new object();                 // 串口操作锁
        private readonly AutoResetEvent _evt = new AutoResetEvent(false); // 串口事件信号量
        private bool isSerialPortOperationInProgress = false;         // 串口操作进行中标志
        private const int CONNECT_TIMEOUT = 2000;                     // PLC连接超时毫秒

        private bool isPLCConnected = false;                          // PLC连接状态
        private bool isScaleConnected = false;                        // 电子秤连接状态

        private StringBuilder scaleBuffer = new StringBuilder();      // 电子秤数据缓存

        private SerialPort scaleSerialPort;                           // 电子秤串口实例
        private SerialPort resistorTesterSerialPort;                  // 电阻测试仪串口实例
        private SerialPort multimeterSerialPort;                      // 万用表串口实例
        private SerialPort numberMeterSerialPort;             //数字绝缘表串口实例
        private const double HIGH_RESIST_THRESHOLD = 1000;            // 绝缘阈值Ω
        private SiemensS7Net siemensPLC;                              // 西门子PLC对象

        private Timer plcRequestTimer = new Timer();                  // PLC请求定时器
        private System.Timers.Timer plcReconnectTimer = new System.Timers.Timer(); // PLC重连定时器
        private readonly System.Diagnostics.Stopwatch _frameReceiveStopwatch = new System.Diagnostics.Stopwatch(); // 帧计时器

        private float _currentWeight = 0.0f;                          // 当前重量缓存

        // PLC地址常量
        private const string PLC_weight = "DB83.DBD8";                // PLC重量地址
        private const string PLC_requestFlag = "DB83.DBX12.0";        // PLC请求标志位
        private const string PLC_resistance1_2 = "DB83.DBD14";        // 1-2脚电阻地址
        private const string PLC_resistance3_4 = "DB83.DBD18";        // 3-4脚电阻地址
        private const string PLC_insulation_resistance = "DB83.DBD22";// 绝缘电阻地址
        private const string PLC_requestFlag1 = "DB83.DBX26.0";       // 第二请求标志位

        //// 电阻测试仪协议常量
        //private const byte FRAME_LENGTH = 8;                          // 协议帧长度
        //private const byte CMD_READ_LOW_RES = 0x02;                   // 低电阻命令
        //private const byte CMD_READ_HIGH_RES = 0x03;                  // 高电阻命令
        //private const byte PARAM_BIDIR_LOW = 0x87;                    // 双向低电阻参数
        //private const byte PARAM_HIGH_RES = 0x92;                     // 高电阻参数
        //private const byte DEV_ADDR_CH1 = 0x01;                       // 通道1地址
        //private const byte DEV_ADDR_CH2 = 0x02;                       // 通道2地址
        //private const byte DEV_ADDR_CH3 = 0x03;                       // 通道3地址
        //private const int FRAME_TIMEOUT = 100;                        // 帧超时毫秒

        //// 电阻测试仪接收缓冲区
        //private readonly List<byte> _resistorRxBuffer = new List<byte>(); // 接收缓存
        //private readonly object _bufferLock = new object();           // 缓存锁
        //private readonly AutoResetEvent _dataReceivedEvent = new AutoResetEvent(false); // 数据接收事件
        #endregion

        #region 窗体事件 包含加载与关闭
        private async void FrmMain_Load(object sender, EventArgs e)   // 窗体加载事件
        {
            LoadConfigFromJson();                                     // 加载JSON配置
            scaleSerialPort = new SerialPort();                       // 创建电子秤串口实例

            if (cmb_Port1.SelectedItem != null)                       // 如果端口下拉框有值
            {
                SerialPortHelper.ForceReleasePort(cmb_Port1.Text);    // 强制释放端口
                Thread.Sleep(500);                                    // 稍等500ms
            }

            await ConnectSerialPortAsync(scaleSerialPort, cmb_Port1, cmb_BaudRate1, cmb_Parity1,
                cmb_StopBits1, cmb_DataBits1, btn_Connect1, btn_DisConnect1,
                new SerialDataReceivedEventHandler(Scale_DataReceived), scaleSerialPortState, panel1);

            await ConnectPLCAsync();                                  // 异步连接PLC


            //resistorTesterSerialPort = new SerialPort();                       // 创建电阻测试仪串口实例

            //if (cmb_Port2.SelectedItem != null)                       // 如果端口下拉框有值
            //{
            //    SerialPortHelper.ForceReleasePort(cmb_Port2.Text);    // 强制释放端口
            //    Thread.Sleep(500);                                    // 稍等500ms
            //}
            //// 调零前禁用
            //btn_Test.Enabled = false;
            //await ConnectSerialPortAsync(resistorTesterSerialPort, cmb_Port2, cmb_BaudRate2, cmb_Parity2,
            //  cmb_StopBits2, cmb_DataBits2, btn_Connect2, btn_DisConnect2,
            //  new SerialDataReceivedEventHandler(ResistorTester_DataReceived), low_resistanceSerialPortState); // 连接电子秤
            //                                                                                                   // 只要电阻测试仪已连接，就立即执行 CH1 & CH2 调零
            //if (resistorTesterSerialPort?.IsOpen == true)
            //{
            //    await ZeroChannelAsync(Dzc9RProtocol.CMD_CHANNEL_1, "1#通道");
            //    await ZeroChannelAsync(Dzc9RProtocol.CMD_CHANNEL_2, "2#通道");
            //}
            //// 调零前禁用
            //btn_Test.Enabled = true;
        }

        private async void FrmMain_FormClosed(object sender, FormClosedEventArgs e) // 窗体关闭事件
        {
            if (scaleSerialPort != null)                              // 如果电子秤串口实例非空
            {
                await Task.Run(() => DisconnectSerialPort(
                    scaleSerialPort,
                    btn_Connect1,
                    btn_DisConnect1,
                    new SerialDataReceivedEventHandler(Scale_DataReceived),
                    scaleSerialPortState,panel1)                             // 异步断开电子秤
                );
            }

            if (resistorTesterSerialPort != null)                     // 如果电阻仪串口实例非空
            {
                await Task.Run(() => DisconnectSerialPort(
                    resistorTesterSerialPort,
                    btn_Connect2,
                    btn_DisConnect2,
                    new SerialDataReceivedEventHandler(ResistorTester_DataReceived),
                    low_resistanceSerialPortState, null)                    // 异步断开电阻仪
                );
            }
            if (multimeterSerialPort != null)                         // 如果万用表串口实例非空
            {
                await Task.Run(() => DisconnectSerialPort(
                    multimeterSerialPort,
                    btn_Connect3,
                    btn_DisConnect3,
                    new SerialDataReceivedEventHandler(ResistorTester_DataReceived),
                    avoMeter_state, null)                                   // 异步断开万用表
                );
            }

            await Task.Run(() => DisconnectPLC());                     // 异步断开PLC
        }
        #endregion

        #region 初始化参数
        private void InitParam()                                       // 初始化所有下拉框及定时器
        {
            #region 串口初始化参数
            string[] portList = SerialPort.GetPortNames();            // 获取可用串口
            if (portList.Length > 0)                                  // 如果有可用串口
            {
                cmb_Port1.Items.AddRange(portList);                   // 填充电子秤端口
                cmb_Port1.SelectedIndex = 0;                          // 默认选第一个
                cmb_Port2.Items.AddRange(portList);                   // 填充电阻仪端口
                cmb_Port2.SelectedIndex = 0;                          // 默认选第一个
                cmb_Port3.Items.AddRange(portList);                   // 填充万用表端口
                cmb_Port3.SelectedIndex = 0;                          // 默认选第一个
                cmb_Port4.Items.AddRange(portList);                   // 填充万用表端口
                cmb_Port4.SelectedIndex = 0;
            }

            string[] baudRates = { "2400", "4800", "9600", "19200", "38400", "115200" }; // 常用波特率
            cmb_BaudRate1.Items.AddRange(baudRates);                  // 电子秤波特率下拉框
            cmb_BaudRate1.SelectedIndex = 2;                          // 默认9600
            cmb_BaudRate2.Items.AddRange(baudRates);                  // 电阻仪波特率下拉框
            cmb_BaudRate2.SelectedIndex = 2;                          // 默认9600
            cmb_BaudRate3.Items.AddRange(baudRates);                  // 万用表波特率下拉框
            cmb_BaudRate3.SelectedIndex = 2;                          // 默认9600
            cmb_BaudRate4.Items.AddRange(baudRates);                  // 万用表波特率下拉框
            cmb_BaudRate4.SelectedIndex = 2;                          // 默认9600

            cmb_Parity1.DataSource = Enum.GetNames(typeof(Parity));   // 电子秤校验位
            cmb_Parity1.SelectedIndex = 0;                            // 默认None
            cmb_Parity2.DataSource = Enum.GetNames(typeof(Parity));   // 电阻仪校验位
            cmb_Parity2.SelectedIndex = 0;                            // 默认None
            cmb_Parity3.DataSource = Enum.GetNames(typeof(Parity));   // 万用表校验位
            cmb_Parity3.SelectedIndex = 0;                            // 默认None
            cmb_Parity4.DataSource = Enum.GetNames(typeof(Parity));   // 万用表校验位
            cmb_Parity4.SelectedIndex = 0;                            // 默认None

            cmb_StopBits1.DataSource = Enum.GetNames(typeof(StopBits)); // 电子秤停止位
            cmb_StopBits1.SelectedIndex = 1;                          // 默认One
            cmb_StopBits2.DataSource = Enum.GetNames(typeof(StopBits)); // 电阻仪停止位
            cmb_StopBits2.SelectedIndex = 1;                          // 默认One
            cmb_StopBits3.DataSource = Enum.GetNames(typeof(StopBits)); // 万用表停止位
            cmb_StopBits3.SelectedIndex = 1;                          // 默认One
            cmb_StopBits4.DataSource = Enum.GetNames(typeof(StopBits)); // 万用表停止位
            cmb_StopBits4.SelectedIndex = 1;                          // 默认One

            cmb_DataBits1.Items.AddRange(new[] { "7", "8" });          // 电子秤数据位
            cmb_DataBits1.SelectedIndex = 1;                          // 默认8
            cmb_DataBits2.Items.AddRange(new[] { "7", "8" });          // 电阻仪数据位
            cmb_DataBits2.SelectedIndex = 1;                          // 默认8
            cmb_DataBits3.Items.AddRange(new[] { "7", "8" });          // 万用表数据位
            cmb_DataBits3.SelectedIndex = 1;
            cmb_DataBits4.Items.AddRange(new[] { "7", "8" });          // 万用表数据位
            cmb_DataBits4.SelectedIndex = 1; // 默认8
            #endregion

            #region 西门子PLC初始化参数
            cmb_CPUType.DataSource = Enum.GetNames(typeof(SiemensPLCS)); // PLC型号下拉框
            txt_IPAddress.Text = "192.168.0.5";                        // 默认PLC IP
            txt_Port.Text = "102";                                     // 默认PLC端口
            txt_Rack.Text = "0";                                       // 默认机架号
            txt_Slot.Text = "0";                                       // 默认槽号
            #endregion

            plcRequestTimer.Interval = 100;                            // PLC轮询100ms
            plcRequestTimer.Tick += PlcRequestTimer_Tick;              // 绑定轮询事件

            plcReconnectTimer.Interval = 5000;                         // 重连定时器5秒
            plcReconnectTimer.Elapsed += PLCReconnectTimer_Elapsed;    // 绑定重连事件

            this.toggle_AutoStart.CheckedChanged += Toggle_AutoStart_CheckedChanged; // 开机自启开关
        }
        #endregion

        #region 电子秤功能
        private async void PlcRequestTimer_Tick(object sender, EventArgs e) // PLC轮询定时器
        {
            try
            {
                if (siemensPLC == null || !isPLCConnected)             // PLC未连接
                {
                    plcRequestTimer.Stop();                            // 停止轮询
                    return;                                            // 退出
                }

                var requestResult = await Task.Run(() => siemensPLC.ReadBool(PLC_requestFlag)); // 读取PLC请求读取称重数据标志
                var requestResult1 = await Task.Run(() => siemensPLC.ReadBool(PLC_requestFlag1));// 读取PLC请求读取电阻测试仪标志
                if (!requestResult.IsSuccess)                           // 读取失败
                {
                    HandlePLCDisconnect();                             // 处理断线
                    return;                                            // 退出
                }

                if (requestResult.Content)                             // 如果PLC请求为true
                {
                    await Task.Run(() =>
                    {
                        siemensPLC.Write(PLC_weight, _currentWeight);  // 写重量
                        siemensPLC.Write(PLC_requestFlag, false);      // 复位请求位
                    });

                    this.BeginInvoke(new Action(() =>
                    {
                        PLC_weightData.Text = _currentWeight.ToString("F1"); // UI显示重量
                    }));
                }
                if (!requestResult1.IsSuccess)                           // 读取失败
                {
                    HandlePLCDisconnect();                             // 处理断线
                    return;                                            // 退出
                }

                if (requestResult1.Content)                             // 如果PLC请求为true
                {
                    await Task.Run(() =>
                    {
                        siemensPLC.Write(PLC_weight, _currentWeight);  // 写重量
                        siemensPLC.Write(PLC_requestFlag1, false);      // 复位请求位
                    });

                    this.BeginInvoke(new Action(() =>
                    {

                        //PLC_12resistanceData.Text = readResult.Content[0].ToString();
                        //PLC_34resistanceData.Text = readResult.Content[1].ToString();
                        //PLC_insulationresistanceData.Text = readResult.Content[2].ToString();
                    }));
                }

            }
            catch
            {
                HandlePLCDisconnect();                                 // 异常断线处理
            }
        }

        #region 电子秤串口数据解析
        private void Scale_DataReceived(object sender, SerialDataReceivedEventArgs e) // 电子秤串口接收
        {
            try
            {
                SerialPort port = (SerialPort)sender;                   // 获取串口对象
                string rawData = port.ReadExisting();                   // 读取全部数据
                scaleBuffer.Append(rawData);                            // 追加到缓存

                string bufferContent = scaleBuffer.ToString();          // 缓存内容
                int crlfIndex = bufferContent.IndexOf("\r\n");          // 查找帧结束

                if (crlfIndex >= 0)                                     // 找到完整帧
                {
                    string packet = bufferContent.Substring(0, crlfIndex + 2); // 提取帧
                    scaleBuffer.Remove(0, crlfIndex + 2);               // 移除已处理
                    this.Invoke(new Action(() => ProcessScaleData(packet))); // UI线程处理
                }
            }
            catch (Exception ex)
            {
                this.Invoke(new Action(() =>
                    UIMessageBox.ShowError($"电子秤串口接收数据失败：{ex.Message}"))); // 错误提示
            }
        }

        private void ProcessScaleData(string packet)                    // 处理电子秤数据
        {
            try
            {
                string displayData = new string(packet.Where(c => c >= 32 && c <= 126).ToArray()); // 过滤可打印字符

                if (!string.IsNullOrWhiteSpace(displayData) && float.TryParse(displayData, out float weight)) // 解析重量
                {
                    _currentWeight = weight;                            // 缓存重量

                    string displayText = $"[{DateTime.Now:HH:mm:ss}] {weight:F1}g"; // 显示格式
                    LB_scaleData.Items.Add(displayText);                // 添加到列表
                    lbl_weight.Text = $"{weight:F1} g";                 // 标签显示
                    SerialPort_weightData.Text = weight.ToString("F1"); // 文本框显示

                    if (LB_scaleData.Items.Count > 100)                 // 超过100条
                    {
                        LB_scaleData.Items.RemoveAt(0);                 // 移除最早
                    }
                    LB_scaleData.TopIndex = LB_scaleData.Items.Count - 1; // 滚动到底
                }
            }
            catch
            {
                // 忽略解析异常
            }
        }
        #endregion
        #endregion

        #region === 电阻测试仪（精简版：仅测 CH1→CH2 双向低电阻） ===
        private const byte DEV_ADDR = 0x01;             // 设备地址
        private const byte PARAM_ZERO = 0x01;           // 调零参数（协议被操作参数）
        private const byte CMD_CH1 = 0x01;              // 通道1命令
        private const byte CMD_CH2 = 0x02;              // 通道2命令
        private const byte PARAM_DOUBLE_RES = 0x03;     // 双向低电阻请求参数（协议7.上位机参数0x03）
        private const byte PARAM_AUTO_RANGE = 0x10;     // 低电阻自动量程设置（协议7.上位机参数0x10）
        private const byte RESP_VAL = 0x87;             // 双向电阻正常测量值响应标识（协议7.下位机参数0x87）
        private const byte RESP_OVERRANGE = 0x85;       // 双向电阻过量程响应标识（协议7.下位机参数0x85）
        private const byte FRAME_LEN = 8;               // 帧长度
        private const int PARSE_DELAY = 500;            // 解析前延时（500ms，确保数据稳定）
        private const int INCOMPLETE_DATA_TIMEOUT = 100;// 不完整数据超时时间(ms)
        private const int COMMAND_INTERVAL = 70;        // 指令发送间隔(ms)
        private const int WAIT_TIMEOUT = 3000;          // 延长超时时间到3秒以便调试
        private const int AFTER_CMD_DELAY = 2000;       // 发送命令后间隔1秒（舍弃旧数据）

        private readonly List<byte> _rxBuf = new List<byte>();          // 接收缓存
        private readonly object _rxLock = new object();                 // 缓存锁
        private readonly AutoResetEvent _rxEvt = new AutoResetEvent(false); // 接收事件
        private bool _ch1OverRange = false;            // 1#通道超量程标志
        private bool _ch2OverRange = false;            // 2#通道超量程标志
        private DateTime _firstByteReceivedTime;       // 首字节接收时间，用于超时检测

        private const byte CMD_CH3 = 0x03;              // 3#通道命令（对应协议"命令"字段，与1#(0x01)、2#(0x02)逻辑一致）
        private const byte PARAM_HIGH_RES = 0x0A;       // 高阻工作模式（协议7.上位机被操作参数：0x0A）
        //private const byte PARAM_HIGH_RES_RANGE = 0x0D; // 高阻量程：R100（协议7.上位机参数：0x0D，可按需改为0x0C/R10、0x0E/R1K）
        private const byte PARAM_START_UPLOAD = 0x0B;   // 开始上传数据（高阻模式需启动仪器输出，协议7.上位机参数：0x0B）
        private const int HIGH_RES_WAIT_TIMEOUT = 5000; // 高阻数据读取超时（5秒，可根据仪器响应速度调整）
        private const int HIGH_RES_POST_CMD_DELAY = 800;// 高阻指令发送后等待仪器稳定的延时（ms）

        // 帧结果类（兼容低版本框架）
        private class FrameResult
        {
            public byte[] FrameData { get; set; }       // 正常测量帧数据（超量程时为null）
            public bool IsOverRange { get; set; }       // 是否超量程
        }

        //测试仪调零按钮
        private async void btn_zero_Click(object sender, EventArgs e)
        {
            btn_Test.Enabled = false;
            if (resistorTesterSerialPort?.IsOpen == true)
            {
                Debug.WriteLine("=== 开始调零流程 ===");
                await ZeroChannelAsync(CMD_CH1, "1#通道");
                await ZeroChannelAsync(CMD_CH2, "2#通道");
                Debug.WriteLine("=== 调零流程结束 ===");
            }
            btn_Test.Enabled = true;
        }

        /// <summary>
        /// 对单个通道执行调零
        /// </summary>
        private async Task ZeroChannelAsync(byte channel, string name)
        {
            byte[] cmd = BuildCommand(DEV_ADDR, channel, PARAM_ZERO);
            for (int i = 0; i < 2; i++)
            {
                byte[] cmdCopy = cmd;
                string hexString = BitConverter.ToString(cmdCopy).Replace("-", " ");
                Debug.WriteLine($"[发送调零指令] 通道{channel} 第{i + 1}次: {hexString}");

                lock (serialPortLock)
                {
                    if (resistorTesterSerialPort.IsOpen)
                        resistorTesterSerialPort.Write(cmdCopy, 0, cmdCopy.Length);
                    else
                        Debug.WriteLine("[发送调零指令] 串口未打开，无法发送指令");
                }
                await Task.Delay(COMMAND_INTERVAL);
            }
            await Task.Delay(2000);
            UIMessageTip.ShowOk($"{name}调零完成!");
        }

        #region 串口接收
        private void ResistorTester_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            var sp = (SerialPort)sender;
            try
            {
                int len = sp.BytesToRead;
                if (len == 0) return;

                byte[] buf = new byte[len];
                int bytesRead = sp.Read(buf, 0, len);
                Debug.WriteLine($"[接收数据] 读取到 {bytesRead} 字节原始数据: {BitConverter.ToString(buf, 0, bytesRead).Replace("-", " ")}");

                lock (_rxLock)
                {
                    if (_rxBuf.Count == 0)
                    {
                        _firstByteReceivedTime = DateTime.Now;
                        Debug.WriteLine($"[接收缓存] 开始新的接收序列，首字节时间: {_firstByteReceivedTime:HH:mm:ss.fff}");
                    }
                    _rxBuf.AddRange(buf.Take(bytesRead));
                    Debug.WriteLine($"[接收缓存] 当前缓存长度: {_rxBuf.Count} 字节");

                    TimeSpan elapsed = DateTime.Now - _firstByteReceivedTime;
                    // 当接收超时且缓存不足一帧时，清空缓存（协议注意3）
                    if (elapsed.TotalMilliseconds > INCOMPLETE_DATA_TIMEOUT && _rxBuf.Count < FRAME_LEN)
                    {
                        Debug.WriteLine($"[接收超时] {INCOMPLETE_DATA_TIMEOUT}ms内未收到完整帧，丢弃{_rxBuf.Count}字节");
                        _rxBuf.Clear();
                    }
                    else if (_rxBuf.Count >= FRAME_LEN)
                    {
                        Debug.WriteLine($"[接收缓存] 缓存中已有 {_rxBuf.Count / FRAME_LEN} 个完整帧，等待处理");
                    }
                }
                _rxEvt.Set();
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"[接收异常] 串口接收数据时发生错误: {ex.Message}");
            }
        }
        #endregion

        #region 组帧+校验
        private byte[] BuildCommand(byte devAddr, byte channel, byte param)
        {
            byte[] frame = new byte[FRAME_LEN];
            frame[1] = 0x00;
            frame[2] = 0x00;
            frame[3] = 0x00;
            frame[4] = 0x00;
            frame[5] = param;  // 【5】被操作参数（功能码）
            frame[6] = devAddr; // 【6】设备地址
            frame[7] = channel; // 【7】命令（通道号）

            // 计算校验和（前7字节的异或，协议6.校验和定义）
            byte chk = 0;
            for (int i = 1; i < FRAME_LEN; i++)
                chk ^= frame[i];
            frame[0] = chk;

            // 调试输出构建的指令
            Debug.WriteLine($"[构建指令] 设备地址:0x{devAddr:X2}, 通道:0x{channel:X2}, 参数:0x{param:X2}, 指令: {BitConverter.ToString(frame).Replace("-", " ")}");
            return frame;
        }

        /// <summary>
        /// 构建双向低电阻请求指令
        /// </summary>
        private byte[] BuildDoubleResCmd(byte channel)
        {
            return BuildCommand(DEV_ADDR, channel, PARAM_DOUBLE_RES);
        }

        /// <summary>
        /// 构建自动量程设置指令
        /// </summary>
        private byte[] BuildAutoRangeCmd(byte channel)
        {
            return BuildCommand(DEV_ADDR, channel, PARAM_AUTO_RANGE);
        }

        private bool VerifyFrame(byte[] f)
        {
            if (f == null)
            {
                Debug.WriteLine("[VerifyFrame] 帧为空");
                return false;
            }

            if (f.Length != FRAME_LEN)
            {
                Debug.WriteLine($"[VerifyFrame] 帧长度错误，期望 {FRAME_LEN} 字节，实际 {f.Length} 字节");
                return false;
            }

            byte chk = 0;
            for (int i = 1; i < FRAME_LEN; i++)
                chk ^= f[i];

            bool checksumValid = chk == f[0];
            if (!checksumValid)
            {
                Debug.WriteLine($"[VerifyFrame] 校验和错误，计算得 0x{chk:X2}，实际 0x{f[0]:X2}");
            }
            return checksumValid;
        }
        #endregion

        #region 顺序测试
        private async void btn_Test_Click(object sender, EventArgs e)
        {
            Debug.WriteLine("=== 开始测试流程 ===");
            btn_zero.Enabled = false;
            btn_Test.Enabled = false;
            _ch1OverRange = false;
            _ch2OverRange = false;

            if (resistorTesterSerialPort?.IsOpen != true)
            {
                Debug.WriteLine("[测试流程] 串口未打开");
                UIMessageBox.ShowWarning("请先连接电阻测试仪串口！");
                btn_zero.Enabled = true;
                return;
            }

            try
            {
                lock (_rxLock)
                {
                    _rxBuf.Clear();
                    Debug.WriteLine("[测试流程] 初始清空接收缓存");
                }

                await MeasureAndShowAsync(CMD_CH1, "1-2脚");
                await MeasureAndShowAsync(CMD_CH2, "3-4脚");

                if (_ch1OverRange || _ch2OverRange)
                {
                    string msg = "测试完成，以下通道超量程：";
                    if (_ch1OverRange) msg += " 1-2脚";
                    if (_ch2OverRange) msg += " 3-4脚";
                    UIMessageTip.ShowWarning(msg);
                }
                else
                {
                    UIMessageTip.ShowOk("全部通道测试完成！");
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"[测试异常] {ex.Message}");
                UIMessageBox.ShowError(ex.Message);
            }
            finally
            {
                btn_Test.Enabled = true;
                btn_zero.Enabled = true;
                Debug.WriteLine("=== 测试流程结束 ===");
            }
        }

        private async Task MeasureAndShowAsync(byte channel, string uiName)
        {
            Debug.WriteLine($"=== 开始测量 {uiName} (通道0x{channel:X2}) ===");
            // 步骤1：发送双向低电阻请求指令（连续2次）
            byte[] cmd = BuildDoubleResCmd(channel);
            for (int i = 0; i < 2; i++)
            {
                string hexString = BitConverter.ToString(cmd).Replace("-", " ");
                Debug.WriteLine($"[发送双向电阻指令] 通道{channel} 第{i + 1}次: {hexString}");

                lock (serialPortLock)
                {
                    if (resistorTesterSerialPort.IsOpen)
                        resistorTesterSerialPort.Write(cmd, 0, cmd.Length);
                    else
                        Debug.WriteLine("[发送双向电阻指令] 串口未打开，无法发送");
                }
                await Task.Delay(COMMAND_INTERVAL);
            }

            // 步骤2：关键修改：发送命令后间隔1秒，舍弃期间的旧数据
            Debug.WriteLine($"[等待旧数据舍弃] 发送命令后间隔{AFTER_CMD_DELAY}ms，期间数据将被清空...");
            await Task.Delay(AFTER_CMD_DELAY); // 1秒延时，等待仪器返回最新数据
                                               // 延时结束后，清空缓存中的旧数据（确保只解析1秒后的新数据）
            lock (_rxLock)
            {
                Debug.WriteLine($"[清空旧数据] 1秒延时结束，清空缓存中 {_rxBuf.Count} 字节旧数据");
                _rxBuf.Clear();
            }

            // 步骤3：等待并解析1秒后的新数据帧
            Debug.WriteLine($"[开始解析新数据] 开始接收1秒后的新帧...");
            FrameResult frameResult = await WaitFrameAsync(channel);
            UITextBox targetTxt = channel == CMD_CH1 ? SerialPort_12resistanceData : SerialPort_34resistanceData;

            if (frameResult.IsOverRange)
            {
                if (channel == CMD_CH1)
                    _ch1OverRange = true;
                else
                    _ch2OverRange = true;

                this.Invoke((Action)(() => targetTxt.Text = "超量程"));
                //UIMessageBox.ShowWarning($"{uiName}超量程！");
                Debug.WriteLine($"[测量结果] {uiName} 超量程");
                return;
            }

            // 步骤4：正确解析数据（协议6a：操作数据【4】【3】【2】【1】，大端序重组）
            uint raw = (uint)(
                frameResult.FrameData[4] << 24 |  // 最高字节（操作数据第4字节）
                frameResult.FrameData[3] << 16 |  // 次高字节（操作数据第3字节）
                frameResult.FrameData[2] << 8 |   // 次低字节（操作数据第2字节）
                frameResult.FrameData[1]          // 最低字节（操作数据第1字节）
            );
            double val = raw * 0.0001;  // 0.1mΩ → Ω（协议单位定义）
            this.Invoke((Action)(() => targetTxt.Text = $"{val:F3} Ω"));
            Debug.WriteLine($"[测量结果] {uiName} 原始值:0x{raw:X8}, 转换后: {val:F3} Ω");

            Debug.WriteLine($"=== 结束测量 {uiName} ===");
        }

        private async Task<FrameResult> WaitFrameAsync(byte channel)
        {
            Debug.WriteLine($"[WaitFrame] 开始等待通道{channel}的1秒后新响应，超时时间 {WAIT_TIMEOUT + PARSE_DELAY}ms");
            var sw = Stopwatch.StartNew();
            int totalFramesChecked = 0;
            byte[] matchedFrame = null; // 用于暂存找到的匹配帧

            while (sw.ElapsedMilliseconds < WAIT_TIMEOUT + PARSE_DELAY)
            {
                // 每500ms输出一次等待状态，帮助调试
                if (sw.ElapsedMilliseconds % 500 == 0)
                {
                    Debug.WriteLine($"[WaitFrame] 已等待 {sw.ElapsedMilliseconds}ms，仍在等待通道{channel}的新响应...");
                }

                if (_rxEvt.WaitOne(50))
                {
                    lock (_rxLock)
                    {
                        // 循环检查所有完整帧（仅处理1秒后的新帧）
                        while (_rxBuf.Count >= FRAME_LEN)
                        {
                            totalFramesChecked++;
                            byte[] f = _rxBuf.Take(FRAME_LEN).ToArray();
                            string frameStr = BitConverter.ToString(f).Replace("-", " ");
                            Debug.WriteLine($"[WaitFrame] 检查第{totalFramesChecked}个新帧: {frameStr}");

                            // 验证帧有效性（校验和、地址、通道必须全部匹配）
                            bool frameValid = VerifyFrame(f);
                            bool addressMatch = f[6] == DEV_ADDR;
                            bool channelMatch = f[7] == channel;

                            Debug.WriteLine($"[WaitFrame] 帧验证: 校验和={frameValid}, 地址匹配={addressMatch}, 通道匹配={channelMatch}");

                            if (frameValid && addressMatch && channelMatch)
                            {
                                // 找到匹配的有效新帧，暂存并退出lock
                                matchedFrame = f;
                                // 移除该帧（避免重复处理）
                                _rxBuf.RemoveRange(0, FRAME_LEN);
                                Debug.WriteLine($"[WaitFrame] 找到通道{channel}的有效新帧，准备处理");
                                break; // 退出内部循环，处理该帧
                            }
                            else
                            {
                                // 无效帧或不匹配的帧，移除并继续（可能是其他通道/模式的数据）
                                Debug.WriteLine($"[WaitFrame] 帧无效或不匹配（非目标通道），移除该帧");
                                _rxBuf.RemoveRange(0, 1); // 逐字节移除，防止帧同步偏移
                            }
                        }
                    }

                    // 关键修复：在lock外部处理await（避免lock内等待）
                    if (matchedFrame != null)
                    {
                        // 解析前延时（确保数据稳定，已移出lock块）
                        await Task.Delay(PARSE_DELAY);
                        Debug.WriteLine($"[WaitFrame] 延时{PARSE_DELAY}ms后，开始解析新帧");

                        // 检查响应类型（必须是双向电阻的有效响应）
                        byte responseParam = matchedFrame[5];
                        Debug.WriteLine($"[WaitFrame] 新帧响应参数:0x{responseParam:X2}");

                        if (responseParam == RESP_VAL)
                        {
                            // 正常双向电阻值
                            return new FrameResult { FrameData = matchedFrame, IsOverRange = false };
                        }
                        else if (responseParam == RESP_OVERRANGE)
                        {
                            // 双向电阻超量程
                            return new FrameResult { FrameData = null, IsOverRange = true };
                        }
                        else
                        {
                            // 非双向电阻响应（如高阻/电压模式），重置继续等待
                            Debug.WriteLine($"[WaitFrame] 新帧为非双向电阻响应（参数0x{responseParam:X2}），继续等待");
                            matchedFrame = null;
                        }
                    }
                }
            }

            // 超时未找到有效新帧
            Debug.WriteLine($"[WaitFrame] 超时！总共检查了{totalFramesChecked}个新帧，未找到通道{channel}的有效响应");
            throw new TimeoutException($"{(channel == CMD_CH1 ? "1" : "2")}# 通道读取超时（已等待{sw.ElapsedMilliseconds}ms，仅解析1秒后数据）");
        }
        #endregion
        #endregion


        #region 电阻测量解析（根据U1251B SCPI协议）

        // 定义测量次数，默认为1次
        private int _measurementCount = 3;

        // 存储测量结果的列表
        private List<double> _measurements = new List<double>();

        // 命令发送间隔时间，单位为毫秒
        private const int COMMAND_INTERVAL_MS = 500;

        // 定义串口接收数据的终止符，CR+LF
        private readonly byte[] _terminator = new byte[] { 0x0D, 0x0A };

        // 定义接收数据的超时时间，单位为毫秒
        private const int RECEIVE_TIMEOUT_MS = 3000;

        // 定义接收数据结果的结构体
        private struct ReceiveResult
        {
            // 接收到的数据是否包含终止符
            public bool HasTerminator;

            // 总共接收到的字节数
            public int TotalReceived;

            // 接收到的所有字节
            public byte[] AllBytes;

            // 终止符前的数据
            public byte[] DataBeforeTerm;

            // 转换为字符串后的原始数据
            public string RawString;
        }

        // 开始电阻测量的按钮点击事件处理方法
        private async void btn_StartResistanceMeasurement_Click(object sender, EventArgs e)
        {
            // 1. 点击后立即禁用按钮
            btn_StartMeasurement.Enabled = false;
            // 清空之前的测量结果
            _measurements.Clear();

            // 更新UI显示，提示正在测量电阻
            lbl_result.Text = "电阻测量中...";

            // 输出调试信息，表示开始电阻测量
            Debug.WriteLine("===== 开始电阻测量 =====");

            try
            {
                // 如果万用表串口非空且已打开，则设置串口读写超时时间
                if (multimeterSerialPort != null && multimeterSerialPort.IsOpen)
                {
                    multimeterSerialPort.ReadTimeout = 2000;
                    multimeterSerialPort.WriteTimeout = 2000;
                    Debug.WriteLine($"✅ 设置串口超时: ReadTimeout={multimeterSerialPort.ReadTimeout}ms");
                }

                // 循环进行测量，次数由_measurementCount决定
                for (int i = 0; i < _measurementCount; i++)
                {
                    // 输出调试信息，表示开始第i+1次测量
                    Debug.WriteLine($"\r\n----- 第{i + 1}次测量 -----");

                    // 彻底清理串口缓冲区，防止数据残留
                    ClearBuffer();

                    // 发送FETC?命令读取当前测量值，FETC?是SCPI协议中的一个查询命令
                    SendCommand("FETC?\r\n");

                    // 接收数据直到找到终止符
                    ReceiveResult result = await ReceiveFromFirstByteToTerminatorAsync();

                    // 打印接收数据的汇总信息
                    PrintReceiveSummary(result);

                    // 解析接收到的电阻数据
                    if (result.HasTerminator)
                    {
                        if (ParseResistanceDataCorrectly(result.RawString, out double resistanceOhms))
                        {
                            // 如果解析成功，将结果添加到_measurements列表
                            _measurements.Add(resistanceOhms);

                            // 将电阻值转换为千欧姆并输出调试信息
                            double resistanceKOhms = resistanceOhms / 1000;
                            Debug.WriteLine($"✅ 解析成功: {resistanceOhms:F6} Ω = {resistanceKOhms:F6} KΩ");

                            //// 将电阻值显示在UI上
                            //lbl_result.Text = $"{resistanceOhms:F2} Ω ({resistanceKOhms:F4} KΩ)";
                        }
                        else
                        {
                            // 如果解析失败，输出调试信息
                            Debug.WriteLine($"⚠️ 解析失败，原始数据: [{result.RawString}]");

                            // 将错误信息显示在UI上
                            lbl_result.Text = "解析失败";
                        }
                    }
                    else if (result.TotalReceived > 0)
                    {
                        // 如果接收到的数据不完整，输出调试信息
                        Debug.WriteLine($"❌ 未找到终止符，所有接收数据: [{result.RawString}]");

                        // 将错误信息显示在UI上
                        lbl_result.Text = "数据不完整";
                    }
                    else
                    {
                        // 如果未接收到任何数据，输出调试信息
                        Debug.WriteLine("❌ 未接收到任何数据");

                        // 将错误信息显示在UI上
                        lbl_result.Text = "无数据";
                    }

                    // 如果不是最后一次测量，等待COMMAND_INTERVAL_MS毫秒再进行下一次测量
                    if (i < _measurementCount - 1)
                        await Task.Delay(COMMAND_INTERVAL_MS);
                }

                // 如果有有效的测量数据，计算并显示平均值
                if (_measurements.Count > 0)
                {
                    // 计算所有测量的平均值
                    double averageOhms = _measurements.Average();

                    // 将平均值转换为千欧姆
                    double averageKOhms = averageOhms / 1000;

                    // 将平均值显示在UI上

                    lbl_result.Text = $"{averageKOhms:F3}KΩ";
                    
                    // 输出调试信息，显示最终结果
                    Debug.WriteLine($"\r\n===== 最终结果: {averageOhms:F2} Ω = {averageKOhms:F4} KΩ =====");
                }
                else
                {
                    // 如果没有有效的测量数据，输出调试信息
                    Debug.WriteLine("\r\n===== 无有效电阻数据 =====");

                    // 将错误信息显示在UI上
                    lbl_result.Text = "无有效数据";
                }
            }
            catch (Exception ex)
            {
                // 如果发生异常，将错误信息显示在UI上
                lbl_result.Text = $"错误: {ex.Message}";

                // 输出调试信息，显示错误信息
                Debug.WriteLine($"❌ 错误: {ex.Message}");

                // 输出堆栈跟踪信息，用于调试
                Debug.WriteLine($"堆栈跟踪: {ex.StackTrace}");
            }
            finally
            {
                // 2. 无论测试成功/失败，最终都恢复按钮可用
                // （使用 await Task.Yield() 确保在UI线程执行，避免跨线程异常）
                await Task.Yield();
                btn_StartMeasurement.Enabled = true;
            }
        }

        // 解析电阻数据的方法
        private bool ParseResistanceDataCorrectly(string data, out double result)
        {
            // 初始化结果为0
            result = 0;

            // 如果数据为空或仅包含空白字符，则返回false
            if (string.IsNullOrWhiteSpace(data))
                return false;

            // 清理数据：去除首尾空白字符和控制字符
            string cleanData = data.Trim().TrimEnd('\r', '\n', ' ', '\t');

            // 输出调试信息，显示清理后的数据
            Debug.WriteLine($"解析原始数据: [{cleanData}]");

            // 检查是否过载，根据协议文档，过载时会返回特定的字符串
            if (cleanData.Contains("9.90000000E+37"))
            {
                // 检测到正过载 (OL)，设置结果为正无穷大
                Debug.WriteLine("⚠️ 检测到正过载 (OL)");
                result = double.PositiveInfinity;
                return true;
            }
            else if (cleanData.Contains("-9.90000000E+37"))
            {
                // 检测到负过载 (OL)，设置结果为负无穷大
                Debug.WriteLine("⚠️ 检测到负过载 (OL)");
                result = double.NegativeInfinity;
                return true;
            }

            // 检查是否为零值电阻
            if (cleanData == "+0.00000000E+00" || cleanData == "0.00000000E+00")
            {
                // 检测到零值电阻，设置结果为0
                Debug.WriteLine("✅ 检测到零值电阻");
                result = 0;
                return true;
            }

            // 解析科学计数法格式（NR3格式）
            try
            {
                // 使用InvariantCulture确保正确解析科学计数法
                bool success = double.TryParse(
                    cleanData,
                    NumberStyles.Float | NumberStyles.AllowExponent | NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint,
                    CultureInfo.InvariantCulture,
                    out result
                );

                // 如果解析成功，输出调试信息
                if (success)
                {
                    Debug.WriteLine($"✅ 科学计数法解析成功: {cleanData} → {result} Ω");
                    return true;
                }
                else
                {
                    // 如果解析失败，输出调试信息
                    Debug.WriteLine($"❌ 无法解析科学计数法: {cleanData}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                // 如果发生异常，输出调试信息
                Debug.WriteLine($"❌ 解析异常: {ex.Message}");
                return false;
            }
        }

        // 异步接收数据直到找到终止符的方法
        private async Task<ReceiveResult> ReceiveFromFirstByteToTerminatorAsync()
        {
            // 初始化接收结果
            ReceiveResult result = new ReceiveResult();

            // 用于存储接收到的所有字节
            List<byte> allBytes = new List<byte>();

            // 设置接收超时时间
            DateTime timeout = DateTime.Now.AddMilliseconds(RECEIVE_TIMEOUT_MS);

            // 标记是否找到终止符
            bool foundTerminator = false;

            // 输出调试信息，表示开始接收数据
            Debug.WriteLine("\r\n----- 开始接收数据（逐字节跟踪） -----");
            Debug.WriteLine("序号 | 十六进制 | 十进制 | ASCII字符 | 说明");
            Debug.WriteLine("------------------------------------------------");

            // 记录接收到的字节数量
            int byteIndex = 0;

            // 标记是否接收到第一个字节
            bool firstByteReceived = false;

            // 记录上一个字节接收时间
            DateTime lastByteTime = DateTime.Now;

            // 循环接收数据，直到找到终止符或超时
            while (DateTime.Now < timeout && !foundTerminator)
            {
                // 检查串口是否有待接收的数据
                if (multimeterSerialPort.BytesToRead > 0)
                {
                    // 读取所有待接收的数据
                    byte[] buffer = new byte[multimeterSerialPort.BytesToRead];
                    int readCount = multimeterSerialPort.Read(buffer, 0, buffer.Length);
                    lastByteTime = DateTime.Now;

                    // 将接收到的数据逐字节处理
                    for (int i = 0; i < readCount; i++)
                    {
                        byte b = buffer[i];
                        allBytes.Add(b);
                        byteIndex++;

                        // 获取字节对应的可读ASCII字符
                        string asciiChar = GetReadableAscii(b);
                        string note = "";

                        // 如果是第一个字节，标记并输出调试信息
                        if (!firstByteReceived)
                        {
                            note = "【第一个字节】";
                            firstByteReceived = true;
                            Debug.WriteLine($"=== 开始接收数据，首字节: 0x{b:X2} ('{asciiChar}') ===");
                        }

                        // 检查是否接收到终止符
                        if (allBytes.Count >= 2)
                        {
                            if (allBytes[allBytes.Count - 2] == _terminator[0] &&
                                allBytes[allBytes.Count - 1] == _terminator[1])
                            {
                                note = "【终止符】";
                                foundTerminator = true;
                            }
                        }

                        // 输出调试信息，显示接收到的每个字节的详细信息
                        Debug.WriteLine($"{byteIndex,3} | 0x{b:X2} | {b,5} | {asciiChar,-12} | {note}");
                    }
                }
                else
                {
                    // 如果已经接收到第一个字节，但超过500ms没有新的数据到达，则认为接收超时
                    if (firstByteReceived && (DateTime.Now - lastByteTime).TotalMilliseconds > 500)
                    {
                        Debug.WriteLine("⚠️ 帧接收超时，停止等待");
                        break;
                    }

                    // 没有数据时等待10毫秒再继续检查
                    await Task.Delay(10);
                }
            }

            // 处理接收结果
            ProcessReceiveResult(ref result, allBytes, foundTerminator);

            // 返回接收结果
            return result;
        }

        // 彻底清理串口缓冲区的方法
        private void ClearBuffer()
        {
            // 如果串口非空且已打开，则清理缓冲区
            if (multimeterSerialPort != null && multimeterSerialPort.IsOpen)
            {
                int totalCleared = 0; // 记录总共清理的字节数
                // 循环清理所有待接收的数据
                while (multimeterSerialPort.BytesToRead > 0)
                {
                    // 每次最多读取1024字节
                    int bytesToRead = Math.Min(multimeterSerialPort.BytesToRead, 1024);
                    byte[] buffer = new byte[bytesToRead];
                    int actuallyRead = multimeterSerialPort.Read(buffer, 0, bytesToRead);
                    totalCleared += actuallyRead;

                    // 如果读取到数据，输出调试信息
                    if (actuallyRead > 0)
                    {
                        Debug.WriteLine($"⚠️ 清理缓冲区: {actuallyRead}字节 - 0x{BitConverter.ToString(buffer, 0, actuallyRead).Replace("-", " 0x")}");
                    }

                    // 等待10毫秒再继续清理
                    Thread.Sleep(10);
                }

                // 如果总共清理了数据，输出调试信息
                if (totalCleared > 0)
                {
                    Debug.WriteLine($"⚠️ 总共清理了 {totalCleared} 字节的残留数据");
                }
            }
        }

        // 以下辅助方法保持不变
        // 处理接收结果的方法
        private void ProcessReceiveResult(ref ReceiveResult result, List<byte> allBytes, bool foundTerminator)
        {
            // 将接收到的所有字节赋值给结果结构体
            result.AllBytes = allBytes.ToArray();

            // 记录总共接收到的字节数
            result.TotalReceived = allBytes.Count;

            // 记录是否找到终止符
            result.HasTerminator = foundTerminator;

            // 如果找到终止符，则将终止符前的数据赋值给结果结构体
            if (foundTerminator && allBytes.Count >= 2)
            {
                result.DataBeforeTerm = allBytes.Take(allBytes.Count - 2).ToArray();
            }
            else
            {
                result.DataBeforeTerm = allBytes.ToArray();
            }

            // 将终止符前的数据转换为字符串
            result.RawString = Encoding.ASCII.GetString(result.DataBeforeTerm);

            // 如果接收到数据，输出调试信息，显示十六进制数据序列
            if (allBytes.Count > 0)
            {
                Debug.WriteLine("\r\n----- 完整接收数据（十六进制序列） -----");
                Debug.WriteLine($"0x{BitConverter.ToString(allBytes.ToArray()).Replace("-", " 0x")}");
                Debug.WriteLine("----------------------------------------");
            }
        }

        // 打印接收数据汇总的方法
        private void PrintReceiveSummary(ReceiveResult result)
        {
            // 输出调试信息，显示接收数据的汇总信息
            Debug.WriteLine("\r\n===== 接收数据汇总 =====");
            Debug.WriteLine($"总接收字节数：{result.TotalReceived}");
            Debug.WriteLine($"是否包含终止符：{result.HasTerminator}");
            Debug.WriteLine($"终止符前数据长度：{result.DataBeforeTerm?.Length ?? 0}字节");
            Debug.WriteLine($"原始数据（终止符前）：[{result.RawString}]");

            // 如果接收到数据，输出调试信息，显示十六进制数据
            if (result.DataBeforeTerm != null && result.DataBeforeTerm.Length > 0)
            {
                Debug.WriteLine($"十六进制数据：0x{BitConverter.ToString(result.DataBeforeTerm).Replace("-", " 0x")}");
            }

            // 输出调试信息，结束汇总信息
            Debug.WriteLine("=======================");
        }

        // 发送命令到串口的方法
        private void SendCommand(string command)
        {
            // 如果串口未打开，抛出InvalidOperationException异常
            if (multimeterSerialPort == null || !multimeterSerialPort.IsOpen)
            {
                Debug.WriteLine("❌ 串口未打开，无法发送命令");
                throw new InvalidOperationException("串口未打开");
            }

            // 将命令字符串转换为字节数组
            byte[] bytes = Encoding.ASCII.GetBytes(command);

            // 发送字节数组到串口
            multimeterSerialPort.Write(bytes, 0, bytes.Length);

            // 输出调试信息，显示发送命令的详细信息
            Debug.WriteLine("\r\n----- 发送命令详情 -----");
            Debug.WriteLine($"命令字符串: {GetReadableString(command)}");
            Debug.WriteLine($"十六进制: 0x{BitConverter.ToString(bytes).Replace("-", " 0x")}");
            Debug.WriteLine($"总字节数: {bytes.Length}");
            Debug.WriteLine("------------------------");
        }

        // 获取可读字符串的方法，用于处理不可打印字符
        private string GetReadableString(string input)
        {
            if (string.IsNullOrEmpty(input))
                return "";

            StringBuilder sb = new StringBuilder();
            foreach (char c in input)
            {
                if (c == '\r') sb.Append("\\r");
                else if (c == '\n') sb.Append("\\n");
                else if (c < 32) sb.Append($"\\x{(int)c:X2}");
                else sb.Append(c);
            }
            return sb.ToString();
        }

        // 获取字节对应的可读ASCII字符的方法
        private string GetReadableAscii(byte b)
        {
            // 检查是否为回车符
            if (b == 0x0D) return "\\r (回车)";

            // 检查是否为换行符
            if (b == 0x0A) return "\\n (换行)";

            // 检查是否为可打印字符
            if (b >= 32 && b <= 126)
                return $"'{Encoding.ASCII.GetString(new[] { b })}'";

            // 如果不是可打印字符，返回十六进制表示
            return $"\\x{b:X2}";
        }

        // 结束电阻测量解析区域
        #endregion













        #region 串口连接管理
        #region 电子秤串口控制
        private async void btn_Connect1_Click(object sender, EventArgs e) // 连接电子秤
        {
            if (isSerialPortOperationInProgress) return;                // 忙碌返回
            scaleSerialPort = new SerialPort();                         // 新建串口
            await ConnectSerialPortAsync(scaleSerialPort, cmb_Port1, cmb_BaudRate1, cmb_Parity1,
                cmb_StopBits1, cmb_DataBits1, btn_Connect1, btn_DisConnect1,
                new SerialDataReceivedEventHandler(Scale_DataReceived), scaleSerialPortState, panel1);
        }

        private void btn_DisConnect1_Click(object sender, EventArgs e)  // 断开电子秤
        {
            if (isSerialPortOperationInProgress) return;                // 忙碌返回
            Task.Run(() => DisconnectSerialPort(
                scaleSerialPort, btn_Connect1, btn_DisConnect1,
                new SerialDataReceivedEventHandler(Scale_DataReceived), scaleSerialPortState, panel1));
        }
        #endregion

        #region 电阻测试仪串口控制
        private async void btn_Connect2_Click(object sender, EventArgs e) // 连接电阻仪
        {
            if (isSerialPortOperationInProgress) return;
            resistorTesterSerialPort = new SerialPort();
            await ConnectSerialPortAsync(resistorTesterSerialPort, cmb_Port2, cmb_BaudRate2, cmb_Parity2,
                cmb_StopBits2, cmb_DataBits2, btn_Connect2, btn_DisConnect2,
                new SerialDataReceivedEventHandler(ResistorTester_DataReceived), low_resistanceSerialPortState, panel2);
        }

        private void btn_DisConnect2_Click(object sender, EventArgs e)  // 断开电阻仪
        {
            if (isSerialPortOperationInProgress) return;
            Task.Run(() => DisconnectSerialPort(
                resistorTesterSerialPort, btn_Connect2, btn_DisConnect2,
                new SerialDataReceivedEventHandler(ResistorTester_DataReceived), low_resistanceSerialPortState, panel2));
        }
        #endregion

        #region 万用表串口连接与断开
        private async void btn_Connect3_Click(object sender, EventArgs e) // 连接万用表
        {
            if (isSerialPortOperationInProgress) return;
            multimeterSerialPort = new SerialPort();
            multimeterSerialPort.Encoding = Encoding.ASCII;

            // 移除DataReceived事件处理程序，使用null代替
            await ConnectSerialPortAsync(multimeterSerialPort, cmb_Port3, cmb_BaudRate3, cmb_Parity3,
                cmb_StopBits3, cmb_DataBits3, btn_Connect3, btn_DisConnect3,
                null, avoMeter_state, panel3); // 改为null
        }

        private void btn_DisConnect3_Click(object sender, EventArgs e)  // 断开万用表
        {
            if (isSerialPortOperationInProgress) return;
            Task.Run(() => DisconnectSerialPort(
                multimeterSerialPort, btn_Connect3, btn_DisConnect3,
                null, avoMeter_state, panel3)); // 改为null
        }
        #endregion

        #region 数字绝缘表串口连接与断开
        private async void btn_Connect4_Click(object sender, EventArgs e) // 连接电子秤
        {
            if (isSerialPortOperationInProgress) return;                // 忙碌返回
            numberMeterSerialPort = new SerialPort();                         // 新建串口
            await ConnectSerialPortAsync(numberMeterSerialPort, cmb_Port4, cmb_BaudRate4, cmb_Parity4,
                cmb_StopBits4, cmb_DataBits4, btn_Connect4, btn_DisConnect4,
                new SerialDataReceivedEventHandler(Scale_DataReceived), scaleSerialPortState, panel4);
        }

        private void btn_DisConnect4_Click(object sender, EventArgs e)  // 断开电子秤
        {
            if (isSerialPortOperationInProgress) return;                // 忙碌返回
            Task.Run(() => DisconnectSerialPort(
                numberMeterSerialPort, btn_Connect1, btn_DisConnect1,
                new SerialDataReceivedEventHandler(Scale_DataReceived), scaleSerialPortState, panel4));
        }
        #endregion

        #region 串口通用操作方法
        private async Task ConnectSerialPortAsync(SerialPort serialPort, UIComboBox portComboBox,
           UIComboBox baudRateComboBox, UIComboBox parityComboBox,
           UIComboBox stopBitsComboBox, UIComboBox dataBitsComboBox,
           UIButton connectButton, UIButton disconnectButton,
           SerialDataReceivedEventHandler dataReceivedHandler, UILedBulb uILedBulb,Panel panel)
        {
            if (isSerialPortOperationInProgress)                      // 忙碌
            {
                UIMessageTip.ShowWarning("操作正在进行中，请稍候...");
                return;
            }

            lock (serialPortLock)                                     // 加锁
            {
                if (isSerialPortOperationInProgress) return;
                isSerialPortOperationInProgress = true;               // 置位忙碌
            }

            try
            {
                connectButton.Enabled = false;                          // 禁用连接按钮
                disconnectButton.Enabled = false;                       // 禁用断开按钮

                SerialPortHelper.ForceReleasePort(portComboBox.Text);   // 强制释放端口
                scaleBuffer.Clear();                                    // 清缓存

                serialPort.PortName = portComboBox.Text;                // 端口名
                serialPort.BaudRate = int.Parse(baudRateComboBox.Text); // 波特率
                serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), parityComboBox.SelectedItem.ToString()); // 校验位
                serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), stopBitsComboBox.SelectedItem.ToString()); // 停止位
                serialPort.DataBits = int.Parse(dataBitsComboBox.Text); // 数据位

                serialPort.DataReceived -= dataReceivedHandler;         // 先解绑
                serialPort.DataReceived += dataReceivedHandler;         // 再绑定

                await Task.Run(() =>                                     // 异步打开
                {
                    try
                    {
                        using (var cts = new CancellationTokenSource(5000)) // 5秒超时
                        {
                            cts.Token.Register(() =>
                            {
                                if (serialPort.IsOpen)
                                {
                                    try { serialPort.Close(); } catch { } // 超时关闭
                                }
                            });
                            serialPort.Open();                          // 打开串口
                        }
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        try
                        {
                            SerialPortHelper.ForceReleasePort(portComboBox.Text); // 再释放
                            Thread.Sleep(500);
                            serialPort.Open();                          // 重试
                        }
                        catch (Exception ex2)
                        {
                            this.Invoke(new Action(() =>
                            {
                                UIMessageTip.ShowError($"串口连接失败：{ex2.Message}");
                            }));
                            throw;
                        }
                    }
                });

                connectButton.Enabled = false;                          // 保持禁用连接
                disconnectButton.Enabled = true;                        // 启用断开
               panel.Enabled= false;
                uILedBulb.On = true;                                    // 指示灯亮
                UIMessageTip.ShowOk("串口已连接");                      // 提示成功
            }
            catch (Exception ex)
            {
                UIMessageTip.ShowError("串口连接失败：" + ex.Message);   // 失败提示
                connectButton.Enabled = true;                           // 恢复连接按钮
                disconnectButton.Enabled = false;                       // 保持禁用断开
            }
            finally
            {
                lock (serialPortLock)
                {
                    isSerialPortOperationInProgress = false;            // 清除忙碌
                }
            }
        }

        private void DisconnectSerialPort(SerialPort serialPort, UIButton connectButton,
     UIButton disconnectButton, SerialDataReceivedEventHandler dataReceivedHandler,
     UILedBulb uILedBulb,Panel panel)
        {
            if (isSerialPortOperationInProgress)                      // 忙碌
            {
                this.Invoke(new Action(() =>
                {
                    UIMessageTip.ShowWarning("操作正在进行中，请稍候...");
                }));
                return;
            }

            lock (serialPortLock)
            {
                if (isSerialPortOperationInProgress) return;
                isSerialPortOperationInProgress = true;               // 置位忙碌
            }

            try
            {
                this.Invoke(new Action(() =>
                {
                    connectButton.Enabled = false;                      // 禁用按钮
                    disconnectButton.Enabled = false;
                }));

                if (serialPort != null)
                {
                    if (dataReceivedHandler != null)
                    {
                        serialPort.DataReceived -= dataReceivedHandler; // 解绑事件
                    }

                    if (serialPort.IsOpen)
                    {
                        var closeTask = Task.Run(() =>
                        {
                            try { serialPort.Close(); } catch { }       // 异步关闭
                        });

                        if (!closeTask.Wait(2000))                      // 超时
                        {
                            SerialPortHelper.ForceReleasePort(serialPort.PortName); // 强制释放
                        }
                    }
                    serialPort.Dispose();                               // 释放
                }

                this.Invoke(new Action(() =>
                {
                    connectButton.Enabled = true;                       // 启用连接
                    disconnectButton.Enabled = false;                   // 禁用断开
                    uILedBulb.On = false;
                    panel.Enabled = true;
                    UIMessageTip.ShowOk("串口已断开");                   // 提示
                }));
                scaleBuffer.Clear();                                    // 清缓存
            }
            catch (Exception ex)
            {
                this.Invoke(new Action(() =>
                {
                    UIMessageTip.ShowError($"断开串口失败：{ex.Message}");
                    connectButton.Enabled = true;                       // 恢复按钮
                    disconnectButton.Enabled = false;
                    panel.Enabled = true;
                }));
            }
            finally
            {
                lock (serialPortLock)
                {
                    isSerialPortOperationInProgress = false;            // 清除忙碌
                }
            }
        }
        #endregion
        #endregion

        #region PLC通信管理
        private void btn_ConnectPLC_Click(object sender, EventArgs e)   // 连接PLC按钮
        {
            _ = ConnectPLCAsync();                                      // 异步连接
        }

        private void btn_DisConnectPLC_Click(object sender, EventArgs e)// 断开PLC按钮
        {
            DisconnectPLC();                                            // 断开
        }

        #region PLC核心操作方法
        private async void PLCReconnectTimer_Elapsed(object sender, ElapsedEventArgs e) // 重连定时器
        {
            try
            {
                if (!isPLCConnected)                                    // 未连接
                {
                    if (this.InvokeRequired)                            // UI线程
                    {
                        this.Invoke((MethodInvoker)delegate
                        {
                            _ = ConnectPLCAsync();                      // 重连
                        });
                    }
                    else
                    {
                        await ConnectPLCAsync();                        // 直接重连
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"PLC重连异常: {ex.Message}");          // 调试输出
            }
        }

        private void DisconnectPLC()                                    // 统一断开PLC
        {
            try
            {
                plcRequestTimer.Stop();                                 // 停止轮询
                plcReconnectTimer.Stop();                               // 停止重连

                if (siemensPLC != null)
                {
                    siemensPLC.ConnectClose();                          // 关闭连接
                    siemensPLC = null;                                  // 置空
                }
                PLCState.On = false;                                    // 指示灯灭
                isPLCConnected = false;                                 // 标记未连接
                btn_ConnectPLC.Enabled = true;                          // 启用连接
                btn_DisConnectPLC.Enabled = false;                      // 禁用断开
                Panel_PLC.Enabled = true;                               // 启用配置面板
                UIMessageTip.ShowOk("PLC断开成功!");                     // 提示
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"断开连接异常: {ex.Message}");          // 调试输出
            }
        }

        private async Task<bool> ConnectPLCAsync()                      // 异步连接PLC
        {
            try
            {
                var plc = new SiemensS7Net((SiemensPLCS)Enum.Parse(
                    typeof(SiemensPLCS),
                    cmb_CPUType.SelectedItem.ToString()));              // 根据下拉框选择PLC型号

                plc.IpAddress = txt_IPAddress.Text.Trim();              // IP
                plc.Port = int.Parse(txt_Port.Text.Trim());             // 端口
                plc.Rack = byte.Parse(txt_Rack.Text.Trim());            // 机架
                plc.Slot = byte.Parse(txt_Slot.Text.Trim());            // 槽位
                plc.ConnectTimeOut = CONNECT_TIMEOUT;                   // 超时

                var connectResult = await Task.Run(() => plc.ConnectServer()); // 连接

                if (connectResult.IsSuccess)                            // 成功
                {
                    siemensPLC = plc;                                   // 保存实例

                    this.Invoke(new Action(() =>
                    {
                        PLCState.On = true;                             // 指示灯亮
                        btn_ConnectPLC.Enabled = false;                 // 禁用连接
                        btn_DisConnectPLC.Enabled = true;               // 启用断开
                        Panel_PLC.Enabled = false;                      // 禁用配置
                        isPLCConnected = true;                          // 标记已连接
                        UIMessageTip.ShowOk("PLC连接成功!");             // 提示
                    }));

                    plcRequestTimer.Start();                            // 启动轮询
                    plcReconnectTimer.Stop();                           // 停止重连
                    return true;                                        // 成功返回
                }
                else
                {
                    plcReconnectTimer.Start();                          // 启动重连
                    return false;                                       // 失败返回
                }
            }
            catch
            {
                return false;                                           // 异常返回
            }
        }

        private void HandlePLCDisconnect()                              // 统一处理PLC断线
        {
            if (isPLCConnected)                                         // 如果之前已连接
            {
                isPLCConnected = false;                                 // 标记未连接
                PLCState.On = false;                                    // 指示灯灭
                btn_ConnectPLC.Enabled = true;                          // 启用连接
                btn_DisConnectPLC.Enabled = false;                      // 禁用断开
                Panel_PLC.Enabled = true;                               // 启用配置

                this.Invoke(new Action(() =>
                {
                    UIMessageTip.ShowError("PLC连接已断开，正在尝试重连..."); // 提示
                }));

                plcRequestTimer.Stop();                                 // 停止轮询
                plcReconnectTimer.Start();                              // 启动重连
            }
        }
        #endregion

        #region PLC测试功能
        private async void btn_read_Click(object sender, EventArgs e)   // 读PLC按钮
        {
            if (!isPLCConnected)                                        // 未连接
            {
                UIMessageBox.ShowError("PLC未连接，请先连接PLC！");
                return;
            }

            try
            {
                this.BeginInvoke(new Action(() => { PLCState.Text = "读取中..."; })); // UI提示

                OperateResult<float> readResult = await Task.Run(() => siemensPLC.ReadFloat("DB83.DBD8")); // 读取位

                if (readResult.IsSuccess)                               // 成功
                {
                    this.BeginInvoke(new Action(() =>
                    {
                        PLC_weightData.Text = readResult.Content.ToString(); // 显示
                        UIMessageTip.ShowOk($"读取成功：{readResult.Content}");
                        PLCState.Text = "读取完成";
                    }));
                }
                else
                {
                    this.BeginInvoke(new Action(() =>
                    {
                        UIMessageBox.ShowError($"读取失败：{readResult.Message}");
                        PLCState.Text = "读取失败";
                    }));
                }
            }
            catch (Exception ex)
            {
                this.BeginInvoke(new Action(() =>
                {
                    UIMessageBox.ShowError($"读取异常：{ex.Message}");
                    PLCState.Text = "异常";
                }));
            }
        }

        private async void btn_write_Click(object sender, EventArgs e)  // 写PLC按钮
        {
            if (!isPLCConnected)                                        // 未连接
            {
                UIMessageBox.ShowError("PLC未连接，请先连接PLC！");
                return;
            }

            try
            {
                string writeValueStr = request_weight.Text.Trim();      // 获取输入
                bool writeValue;

                if (writeValueStr == "0")                               // 输入0
                {
                    writeValue = false;
                }
                else if (writeValueStr == "1")                          // 输入1
                {
                    writeValue = true;
                }
                else
                {
                    UIMessageBox.ShowError("请输入 0 或 1！");         // 输入错误
                    return;
                }

                this.BeginInvoke(new Action(() => { PLCState.Text = "写入中..."; })); // UI提示

                OperateResult writeResult = await Task.Run(() => siemensPLC.Write("DB83.DBX12.0", writeValue)); // 写入

                if (writeResult.IsSuccess)                              // 成功
                {
                    this.BeginInvoke(new Action(() =>
                    {
                        UIMessageTip.ShowOk($"写入成功：{writeValue}");
                        PLCState.Text = "写入完成";
                    }));
                }
                else
                {
                    this.BeginInvoke(new Action(() =>
                    {
                        UIMessageBox.ShowError($"写入失败：{writeResult.Message}");
                        PLCState.Text = "写入失败";
                    }));
                }
            }
            catch (Exception ex)
            {
                this.BeginInvoke(new Action(() =>
                {
                    UIMessageBox.ShowError($"写入异常：{ex.Message}");
                    PLCState.Text = "异常";
                }));
            }
        }

        private async void btn_read1_Click(object sender, EventArgs e)  // 读第二请求位
        {
            /* 以下与btn_read_Click类似，仅地址不同，注释略 */
            if (!isPLCConnected)
            {
                UIMessageBox.ShowError("PLC未连接，请先连接PLC！");
                return;
            }

            try
            {
                this.BeginInvoke(new Action(() => { PLCState.Text = "读取中..."; }));

                OperateResult<float[]> readResult = await Task.Run(() => siemensPLC.ReadFloat("DB83.DBD14", 3));

                if (readResult.IsSuccess)
                {
                    this.BeginInvoke(new Action(() =>
                    {
                        PLC_12resistanceData.Text = readResult.Content[0].ToString();
                        PLC_34resistanceData.Text = readResult.Content[1].ToString();
                        PLC_1insulationresistanceData.Text = readResult.Content[2].ToString();
                        UIMessageTip.ShowOk($"读取成功：{readResult.Content}");
                        PLCState.Text = "读取完成";
                    }));
                }
                else
                {
                    this.BeginInvoke(new Action(() =>
                    {
                        UIMessageBox.ShowError($"读取失败：{readResult.Message}");
                        PLCState.Text = "读取失败";
                    }));
                }
            }
            catch (Exception ex)
            {
                this.BeginInvoke(new Action(() =>
                {
                    UIMessageBox.ShowError($"读取异常：{ex.Message}");
                    PLCState.Text = "异常";
                }));
            }
        }

        private async void btn_write1_Click(object sender, EventArgs e) // 写第二请求位
        {
            /* 与btn_write_Click类似，仅地址不同，注释略 */
            if (!isPLCConnected)
            {
                UIMessageBox.ShowError("PLC未连接，请先连接PLC！");
                return;
            }

            try
            {
                string writeValueStr = request_resistance.Text.Trim();
                bool writeValue;

                if (writeValueStr == "0")
                {
                    writeValue = false;
                }
                else if (writeValueStr == "1")
                {
                    writeValue = true;
                }
                else
                {
                    UIMessageBox.ShowError("请输入 0 或 1！");
                    return;
                }

                this.BeginInvoke(new Action(() => { PLCState.Text = "写入中..."; }));

                OperateResult writeResult = await Task.Run(() => siemensPLC.Write(PLC_requestFlag1, writeValue));

                if (writeResult.IsSuccess)
                {
                    this.BeginInvoke(new Action(() =>
                    {
                        UIMessageTip.ShowOk($"写入成功：{writeValue}");
                        PLCState.Text = "写入完成";
                    }));
                }
                else
                {
                    this.BeginInvoke(new Action(() =>
                    {
                        UIMessageBox.ShowError($"写入失败：{writeResult.Message}");
                        PLCState.Text = "写入失败";
                    }));
                }
            }
            catch (Exception ex)
            {
                this.BeginInvoke(new Action(() =>
                {
                    UIMessageBox.ShowError($"写入异常：{ex.Message}");
                    PLCState.Text = "异常";
                }));
            }
        }
        #endregion
        #endregion

        #region 系统配置管理
        private void btn_SaveConfig_Click(object sender, EventArgs e)   // 保存配置按钮
        {
            SaveConfigToJson();                                         // 保存
        }

        #region 配置文件操作
        private void SaveConfigToJson()                                 // 保存配置到JSON
        {
            try
            {
                var config = new AppConfig                              // 构造配置对象
                {
                    Port1Config = new PortConfig                        // 电子秤
                    {
                        Description = "电子秤串口配置",
                        PortName = cmb_Port1.Text,
                        BaudRate = int.Parse(cmb_BaudRate1.Text),
                        Parity = GetSelectedItemText(cmb_Parity1),
                        StopBits = GetSelectedItemText(cmb_StopBits1),
                        DataBits = int.Parse(cmb_DataBits1.Text),
                    },
                    Port2Config = new PortConfig                        // 电阻仪
                    {
                        Description = "电阻测试仪串口配置",
                        PortName = cmb_Port2.Text,
                        BaudRate = int.Parse(cmb_BaudRate2.Text),
                        Parity = GetSelectedItemText(cmb_Parity2),
                        StopBits = GetSelectedItemText(cmb_StopBits2),
                        DataBits = int.Parse(cmb_DataBits2.Text),
                    },
                    Port3Config = new PortConfig                        // 万用表
                    {
                        Description = "万用表串口配置",
                        PortName = cmb_Port3.Text,
                        BaudRate = int.Parse(cmb_BaudRate3.Text),
                        Parity = GetSelectedItemText(cmb_Parity3),
                        StopBits = GetSelectedItemText(cmb_StopBits3),
                        DataBits = int.Parse(cmb_DataBits3.Text),
                    },
                    Port4Config = new PortConfig                        // 数字绝缘表
                    {
                        Description = "数字绝缘表串口配置",
                        PortName = cmb_Port4.Text,
                        BaudRate = int.Parse(cmb_BaudRate4.Text),
                        Parity = GetSelectedItemText(cmb_Parity4),
                        StopBits = GetSelectedItemText(cmb_StopBits4),
                        DataBits = int.Parse(cmb_DataBits4.Text),
                    },
                    PLCConfig = new PLCConfig                           // PLC
                    {
                        Description = "PLC配置",
                        CPUType = (SiemensPLCS)Enum.Parse(typeof(SiemensPLCS), cmb_CPUType.SelectedItem?.ToString()),
                        IPAddress = txt_IPAddress.Text,
                        Port = int.Parse(txt_Port.Text),
                        Rack = byte.Parse(txt_Rack.Text),
                        Slot = byte.Parse(txt_Slot.Text),
                    },
                    elseConfig = new ElseConfig                         // 其他
                    {
                        Description = "程序开机自动运行",
                        AutoStart = toggle_AutoStart.Checked,
                    },
                    ConfigDescription = "系统配置文件"
                };

                File.WriteAllText("config.json", JsonConvert.SerializeObject(config, Formatting.Indented)); // 写文件
                UIMessageTip.ShowOk("保存配置成功！");                   // 提示
            }
            catch (Exception ex)
            {
                UIMessageBox.ShowError("保存配置失败：" + ex.Message);    // 异常提示
            }
        }

        private string GetSelectedItemText(UIComboBox comboBox)         // 获取下拉框文本
        {
            var selectedItem = comboBox.SelectedItem;
            return selectedItem != null ? selectedItem.ToString() : string.Empty;
        }

        private void LoadConfigFromJson()                               // 加载配置
        {
            try
            {
                if (File.Exists("config.json"))                         // 文件存在
                {
                    var config = JsonConvert.DeserializeObject<AppConfig>(File.ReadAllText("config.json")); // 反序列化
                    if (config != null)
                    {
                        /* 以下逐行赋值，注释略 */
                        cmb_Port1.Text = config.Port1Config.PortName;
                        cmb_BaudRate1.Text = config.Port1Config.BaudRate.ToString();
                        cmb_Parity1.SelectedItem = config.Port1Config.Parity;
                        cmb_StopBits1.SelectedItem = config.Port1Config.StopBits;
                        cmb_DataBits1.Text = config.Port1Config.DataBits.ToString();

                        cmb_Port2.Text = config.Port2Config.PortName;
                        cmb_BaudRate2.Text = config.Port2Config.BaudRate.ToString();
                        cmb_Parity2.SelectedItem = config.Port2Config.Parity;
                        cmb_StopBits2.SelectedItem = config.Port2Config.StopBits;
                        cmb_DataBits2.Text = config.Port2Config.DataBits.ToString();

                        cmb_Port3.Text = config.Port3Config.PortName;
                        cmb_BaudRate3.Text = config.Port3Config.BaudRate.ToString();
                        cmb_Parity3.SelectedItem = config.Port3Config.Parity;
                        cmb_StopBits3.SelectedItem = config.Port3Config.StopBits;
                        cmb_DataBits3.Text = config.Port3Config.DataBits.ToString();

                        cmb_Port4.Text = config.Port4Config.PortName;
                        cmb_BaudRate4.Text = config.Port4Config.BaudRate.ToString();
                        cmb_Parity4.SelectedItem = config.Port4Config.Parity;
                        cmb_StopBits4.SelectedItem = config.Port4Config.StopBits;
                        cmb_DataBits4.Text = config.Port4Config.DataBits.ToString();

                        cmb_CPUType.SelectedItem = config.PLCConfig.CPUType.ToString();
                        txt_IPAddress.Text = config.PLCConfig.IPAddress;
                        txt_Port.Text = config.PLCConfig.Port.ToString();
                        txt_Rack.Text = config.PLCConfig.Rack.ToString();
                        txt_Slot.Text = config.PLCConfig.Slot.ToString();

                        toggle_AutoStart.Checked = config.elseConfig.AutoStart;
                    }
                }
            }
            catch (Exception ex)
            {
                UIMessageBox.ShowError("加载配置失败：" + ex.Message);
            }
        }
        #endregion
        #endregion

        #region 系统功能
        #region 开机自启
        private void Toggle_AutoStart_CheckedChanged(object sender, EventArgs e) // 自启开关
        {
            AutoStart(this.toggle_AutoStart.Checked);
        }

        private void AutoStart(bool isAuto = true)                      // 设置开机自启
        {
            try
            {
                using (RegistryKey R_local = Registry.CurrentUser)      // 当前用户注册表
                using (RegistryKey R_run = R_local.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"))
                {
                    if (isAuto)                                         // 启用
                    {
                        R_run.SetValue("PressurizationStationPro", Application.ExecutablePath);
                    }
                    else                                                // 禁用
                    {
                        R_run.DeleteValue("PressurizationStationPro", false);
                    }
                }
            }
            catch (Exception ex)
            {
                UIMessageBox.ShowError($"设置开机自启失败：{ex.Message}");
            }
        }




        #endregion

        #endregion

    }
}